//! This is a simple example of 
//! 1. create_signal + 闭包
//! 2. create_resource + async fn
//! 3. #[server("SendNortify","/api")]
//! 4. create_action + async fn.
//! 5. Await 组件
//! 
use common::ChatHistory;
use leptos::*;
use serde::*;
use chrono::prelude::*;
use leptos_meta::Title;
use anyhow::bail;
use web_sys;
// use leptos::{html::Input, *};
use thiserror::Error;
use anyhow::Result;
use reqwest::header::HeaderMap;
// use gloo_storage::{LocalStorage, Storage};

#[component]
pub fn ChatView2() -> impl IntoView {
  
    let (msg, set_msg) = create_signal(String::new());        
    let his_init:Vec<ChatHistory> = vec![];
    let (his, set_his) = create_signal(his_init );
    
    spawn_local(async move {            
          let r = get_chat_glm().await;          
          if let Ok(r) = r { 
              if r.len() > 0 {
                set_his.set(r);
              }
          }          
      });

    view! {
      <div align="center">          
      <div>"前端直接发起Chat请求，并保存结果到后端的逻辑： "</div>
      <input type="text" size="50" placeholder="input your question!"  id="inputbox" on:input=move |ev| set_msg.set(event_target_value(&ev)) />          
        <button  style="margin:10px"   on:click=move |_| {
          let new_input = msg.get();
          logging::log!("input is {}", new_input);
          if new_input.len() > 0 {
            
            let chatview = document().get_element_by_id("waitingview").unwrap();
            chatview.set_inner_html("<div>  <p class=\"wait-tips\">Waiting ... ...!</p> </div>");

            spawn_local(async move {            
              let r = new_chat_glm(&new_input).await;
              if let Ok(r) = r{
                  if r.question.len() > 0 && r.response.len() > 0 {
                    let mut his_v =  his.get();
                    let mut his_new = vec![r];
                    his_new.append(&mut his_v);                    
                    set_his.set(his_new);
                  }
              }else{
                logging::log!("new_chat_glm error: {:#?}", r);
              }
              let chatview = document().get_element_by_id("waitingview").unwrap();
              chatview.set_inner_html("<br/>");
              reset_input("inputbox", "");
          });

          }else{
            logging::log!("input is empty! {}", get_input_value("inputbox"));
          }          
        }>提问</button>       
      </div>

      <div id="waitingview"> </div>  
      <div id="chatview" align="left"> 
      <Transition>  
      { move|| {
          let hiss = his.get();
          hiss.into_iter().map(|s| {
                      view! {
                              <div class="chat-line" >
                                  <strong>Ask:</strong>
                                  <p>
                                  {s.question}" [" { s.timestamp } "]"
                                  </p>
                              </div>
                              <div class="chat-line">
                                  <strong>Answer:</strong>
                                  <p>{s.response}</p>
                                  <hr style= "border:1px dashed;" />
                              </div>
                          }
                      })
                      .collect::<Vec<_>>()       
            }
      }
      </Transition>

    </div>       
      
    }

}

  /**
   * 重置指定ID的输入框（type=input）的值。
   * @param input_id
   * @param val
   * @spec: 这里提供了一种基于 js_sys::eval(js_code) ，执行js代码的方法或途径。
   */
  fn reset_input(input_id: &str, val:&str) {    
    let js_src = format!("document.getElementById('{}').value ='{}'", input_id, val); 
    web_sys::js_sys::eval(&js_src).ok();  
  }
  /**
   * 获取指定ID的输入框（type=input）的值。
   * @param input_id
   * @spec: 这里提供了一种基于 js_sys::eval(js_code) ，执行js代码的方法或途径。
   */
  fn get_input_value(input_id: &str)->String {  
    let js_src = format!("document.getElementById('{}').value", input_id); 
    let s = web_sys::js_sys::eval(&js_src).unwrap();  
    match s.as_string(){
      Some(s) => return s,
      None => return "".to_string(),
    }
  }
  
  async fn new_chat_glm(msg: &str) -> anyhow::Result< ChatHistory> {

    let rc = chat_with_glm_fe(msg).await?;

    let host = window().location().host().unwrap();    
    let api = format!("http://{}/api/add_chat_glm", host);
    logging::log!("api = {:#?}", api);
    let client = reqwest::Client::new();
    let mut headers = HeaderMap::new();
    headers.insert("Authorization", "Bearer abc".parse()?);
    headers.insert("Content-Type", "application/json; charset=utf-8".parse()?);


    let r  = client
        .post(&api)
        .headers(headers)
        .json(&rc)
        .send()
        .await?
        .text()
        .await?;

    logging::log!("yes, saved, {}", r);        
    return Ok(rc);
  }

  async fn get_chat_glm() -> anyhow::Result< Vec< ChatHistory >> {

    let host = window().location().host().unwrap();
    // let r = web_sys::js_sys::eval("window.location.host");
    let api = format!("http://{}/api/get_glm_chat", host);
    logging::log!("api = {:#?}", api);
    let client = reqwest::Client::new();
    let mut headers = HeaderMap::new();
    headers.insert("Authorization", "Bearer abc".parse()?);
    headers.insert("Content-Type", "application/json; charset=utf-8".parse()?);


    let r: Vec<ChatHistory> = client
        .get(&api)
        .headers(headers)
        .send()
        .await?
        .json()
        .await?;

    logging::log!("get chat history, count={}", r.len());        
    return Ok(r);
  }


/**
 * 简单调用GLM开方接口，采用glm-4-flash模型，进行对话。
 */
async fn chat_with_glm_fe(msg: &str) -> anyhow::Result< ChatHistory > {
    use common::{GlmRequestParam, GlmResponse, GlmMessage};

    if msg.is_empty(){
      bail!("msg is empty");
    }
    let client = reqwest::Client::new();
    let api = "https://open.bigmodel.cn/api/paas/v4/chat/completions";

    let mut headers = HeaderMap::new();
    headers.insert(
        "Authorization",
        "Bearer efee28671779b38ba107b5a8f89491cc.V2R8xEzrqo5FG8RT".parse()?,
    );
    headers.insert("Content-Type", "application/json; charset=utf-8".parse()?);

    let messages = vec![GlmMessage {
        role: "user".to_string(),
        content: msg.to_string(),
    }];

    // logging::log!("{:#?}", messages);

    let askmsg: GlmRequestParam = GlmRequestParam {
        model: "glm-4-flash".to_string(),
        messages,
        temperature: 0.9,
    };

    let r: GlmResponse = client
        .post(api)
        .headers(headers)
        .json(&askmsg)
        .send()
        .await?
        .json()
        .await?;
    // logging::log!("{:#?}", r);
 
    if r.choices.len() > 0 {
      if r.choices.len() > 1 {
          logging::log!("response msg is more than 1, but only use the first one now!");
      }
      let choice = r.choices[0].clone();
      let content = choice.message.content;
      let rc = ChatHistory {
            id: 0,
          question: msg.to_string(),
          response: content,
          timestamp: Local::now().format("%Y%m%d %H:%M:%S").to_string(),
      }; 
      logging::log!("chat to bigmodel.cn/api/paas/v4/chat is OK: {:#?}", rc);
      return Ok(rc);
    }
    bail!("response msg is empty");
}
